﻿#include "SnowYeti.h"
#include "../../../Shared/Functions/Functions.h"
#include "../../MirEnvir/Envir.h"
#include "../../../Shared/Enums.h"
#include "../../../Shared/Data/Stat.h"
#include "../../../Shared/ServerPackets.h"
#include "../DelayedAction.h"
#include "../MapObject.h"
#include "../../Settings.h"

using namespace Server::MirDatabase;
using namespace Server::MirEnvir;
namespace S = ServerPackets;

namespace Server::MirObjects::Monsters
{

    SnowYeti::SnowYeti(MonsterInfo *info) : MonsterObject(info)
    {
    }

    bool SnowYeti::InAttackRange()
    {
        return getCurrentMap() == getTarget()->getCurrentMap() && Functions::InRange(getCurrentLocation(), getTarget()->getCurrentLocation(), 1);
    }

    bool SnowYeti::InRangeAttackRange()
    {
        return getCurrentMap() == getTarget()->getCurrentMap() && Functions::InRange(getCurrentLocation(), getTarget()->getCurrentLocation(), AttackRange);
    }

    void SnowYeti::ProcessTarget()
    {
        if (getTarget() == nullptr || Dead)
        {
            return;
        }

        if (!InAttackRange())
        {
            if (getCanAttack())
            {
                if (getEnvir()->Random->Next(5) == 0)
                {
                    RangeAttack();
                }
            }
            if (getCurrentLocation() == getTarget()->getCurrentLocation())
            {
                MirDirection direction = static_cast<MirDirection>(getEnvir()->Random->Next(8));
                int rotation = getEnvir()->Random->Next(2) == 0 ? 1 : -1;

                for (int d = 0; d < 8; d++)
                {
                    if (Walk(direction))
                    {
                        break;
                    }

                    direction = Functions::ShiftDirection(direction, rotation);
                }
            }
            else
            {
                MoveTo(getTarget()->getCurrentLocation());
            }
        }

        if (!getCanAttack())
        {
            return;
        }

        if (getEnvir()->Random->Next(5) > 0)
        {
            if (InAttackRange())
            {
                Attack();
            }
        }
        else
        {
            RangeAttack();
        }

        if (getEnvir()->getTime() < ShockTime)
        {
            setTarget(nullptr);
            return;
        }
    }

    void SnowYeti::Attack()
    {

        if (!getTarget()->IsAttackTarget(this))
        {
            setTarget(nullptr);
            return;
        }

        int damage = GetAttackPower(Stats[Stat::MinDC], Stats[Stat::MaxDC]);
        if (damage == 0)
        {
            return;
        }

        setDirection(Functions::DirectionFromPoint(getCurrentLocation(), getTarget()->getCurrentLocation()));
        S::ObjectAttack *tempVar = new S::ObjectAttack();
        tempVar->ObjectID = ObjectID;
        tempVar->Direction = getDirection();
        tempVar->Location = getCurrentLocation();
        Broadcast(tempVar);
        DelayedAction *action = new DelayedAction(DelayedType::Damage, getEnvir()->getTime() + 500, {getTarget(), damage, DefenceType::ACAgility});
        ActionList.push_back(action);

        S::ObjectAttack *tempVar2 = new S::ObjectAttack();
        tempVar2->ObjectID = ObjectID;
        tempVar2->Direction = getDirection();
        tempVar2->Location = getCurrentLocation();
        tempVar2->Type = 1;
        Broadcast(tempVar2);
        action = new DelayedAction(DelayedType::Damage, getEnvir()->getTime() + 1500, {getTarget(), damage, DefenceType::ACAgility});
        ActionList.push_back(action);


        ActionTime = getEnvir()->getTime() + 1500;
        AttackTime = getEnvir()->getTime() + AttackSpeed;
        ShockTime = 0;


//C# TO C++ CONVERTER TODO TASK: A 'delete tempVar2' statement was not added since tempVar2 was passed to a method or constructor. Handle memory management manually.
//C# TO C++ CONVERTER TODO TASK: A 'delete action' statement was not added since action was passed to a method or constructor. Handle memory management manually.
//C# TO C++ CONVERTER TODO TASK: A 'delete tempVar' statement was not added since tempVar was passed to a method or constructor. Handle memory management manually.
    }

    void SnowYeti::RangeAttack()
    {
        if (!getTarget()->IsAttackTarget(this))
        {
            setTarget(nullptr);
            return;
        }

        ShockTime = 0;
        ActionTime = getEnvir()->getTime() + 1000;
        AttackTime = getEnvir()->getTime() + AttackSpeed + 1000;
        int damage = GetAttackPower(Stats[Stat::MinDC], Stats[Stat::MaxDC]);
        if (damage == 0)
        {
            return;
        }

        setDirection(Functions::DirectionFromPoint(getCurrentLocation(), getTarget()->getCurrentLocation()));

        int delay = Functions::MaxDistance(getCurrentLocation(), getTarget()->getCurrentLocation()) * 50 + 500; //50 MS per Step

        S::ObjectRangeAttack *tempVar = new S::ObjectRangeAttack();
        tempVar->ObjectID = ObjectID;
        tempVar->Direction = getDirection();
        tempVar->Location = getCurrentLocation();
        tempVar->TargetID = getTarget()->ObjectID;
        Broadcast(tempVar);
        if (damage == 0)
        {
//C# TO C++ CONVERTER TODO TASK: A 'delete tempVar' statement was not added since tempVar was passed to a method or constructor. Handle memory management manually.
            return;
        }
        DelayedAction *action = new DelayedAction(DelayedType::RangeDamage, getEnvir()->getTime() + delay, {getTarget(), damage, DefenceType::MAC});
        ActionList.push_back(action);

//C# TO C++ CONVERTER TODO TASK: A 'delete action' statement was not added since action was passed to a method or constructor. Handle memory management manually.
//C# TO C++ CONVERTER TODO TASK: A 'delete tempVar' statement was not added since tempVar was passed to a method or constructor. Handle memory management manually.
    }

    void SnowYeti::CompleteRangeAttack(std::vector<std::any> &data)
    {
        MapObject *target = std::any_cast<MapObject*>(data[0]);
        int damage = std::any_cast<int>(data[1]);
        DefenceType defence = std::any_cast<DefenceType>(data[2]);

        if (target == nullptr || !target->IsAttackTarget(this) || target->getCurrentMap() != getCurrentMap() || target->Node == nullptr)
        {
            return;
        }

        if (target->Attacked(this, damage, DefenceType::MAC) > 0)
        {
            if (getEnvir()->Random->Next(Settings::PoisonResistWeight) >= target->Stats[Stat::PoisonResist])
            {
                if (getEnvir()->Random->Next(3) == 0)
                {
                    Poison *tempVar = new Poison(), *this;
                    tempVar->PType = PoisonType::Frozen;
                    tempVar->Duration = 5;
                    tempVar->TickSpeed = 1000;
                    target->ApplyPoison(tempVar, this);

//C# TO C++ CONVERTER TODO TASK: A 'delete tempVar' statement was not added since tempVar was passed to a method or constructor. Handle memory management manually.
                }
            }
        }
    }
}
